package nl.utwente.ewi.hmi.multitouch.util;

import java.nio.BufferUnderflowException;

/**
 * The IntQueue class provides an interface to handling a queue of the primitive int type in an
 * efficient manner. The IntQueue is backed by an int array which expands whenever the IntQueue size
 * would overflow. 
 * 
 * @author Michiel Hakvoort
 */
public class IntQueue {

	private int[] queue;
	private int capacity;

	private int head;
	private int size;

	public IntQueue(int capacity) {
		if (capacity < 0) {
        	throw new IllegalArgumentException("Illegal Capacity: "+ capacity);
		}

		this.head = 0;
		this.size = 0;

		this.capacity = capacity;
		this.queue = new int[capacity];
	}

	public IntQueue() {
		this(10);
	}

	public void offer(int value) {
		if(size == capacity) {
			grow();
		}

		queue[(head + size) % capacity] = value;
		size++;
	}

	public void clear() {
		size = 0;
	}

	private void grow() {
		int capacity = (this.capacity * 3) / 2 + 1;
		
		int[] queue = new int[capacity];
		
		if(head + size <= this.capacity) {
			// Copy the entire queue to it's new destination
			System.arraycopy(this.queue, 0, queue, 0, this.capacity);
		} else {

			// Copy the left half of the array
			System.arraycopy(this.queue, 0, queue, 0, (head + size) % this.capacity);

			// Copy the right half of the array
			System.arraycopy(this.queue, head, queue, head - this.capacity + capacity, this.capacity - head);
			head += (capacity - this.capacity);
		}
		
		
		this.queue = queue;
		this.capacity = capacity;
	}
	
	public boolean isEmpty() {
		return size == 0;
	}

	public int poll() {
		if(size == 0) {
			throw new BufferUnderflowException();
		}

		int retVal = queue[head];
		head = (head + 1) % capacity;
		size--;
		return retVal;
	}

	public int shift() {
		if(size == 0) {
			throw new BufferUnderflowException();
		}

		int retVal = queue[(head + size-1) % capacity];
		size--;
		return retVal;
	}
}